package com.liangdemo.web.threadPool;

import java.time.LocalDateTime;
import java.util.concurrent.*;

/**
 * Executors自动创建线程池
 * 
 * @author: LiangErLe
 * @date: 2022/10/27
 **/
public class ExecutorsThreadPool {

    /**
     * newFixedThreadPool 创建固定大小的线程池.
     * 
     * 存在问题：没有对主线程进行控制，会导致主线程在子线程执行完之后在去执行
     */
    public void test1() {
        // 创建大小为5的线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        System.out.println("任务一开始执行");
        // 使用线程执行任务一
        for (int i = 0; i < 5; i++) {
            // 给线程添加任务
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    // 线程名有多少个，cpu就创建了多少线程
                    System.out.println("线程名" + Thread.currentThread().getName() + "在执行任务1");
                }
            });
        }
        System.out.println("任务一执行完成");
        // 使用线程执行任务二
        for (int i = 0; i < 8; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程名" + Thread.currentThread().getName() + "正在执行任务2");
                }
            });
        }
    }

    /**
     * newFixedThreadPool ：自带缓存池
     *
     * 适用于短时间有大量任务的场景， 有可能会占用大量资源，线程数量随着任务量而定
     */
    public void test1_1() {
        // 创建线程池
        ExecutorService service = Executors.newCachedThreadPool();
        // 有50个任务
        for (int i = 0; i < 50; i++) {
            int a = i;
            service.submit(() -> {
                System.out.println(a + "线程名" + Thread.currentThread().getName());
            });
        }
    }

    /**
     * newSingleThreadExecuto:创建单个线程
     *
     * 优点：1，不需要频繁创建和销毁。2.也提供了任务队列和拒绝策略
     */
    public void test2() {
        ExecutorService service = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            int a = i;
            service.submit(() -> {
                // CPU只创建了1个线程，名称始终一样
                System.out.println(a + "线程名" + Thread.currentThread().getName());
            });
        }
    }

    /**
     * newSingleThreadScheduledExecutor:创建定时任务单线程池
     */
    public void test3() {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        System.out.println("添加任务" + LocalDateTime.now());
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务：" + LocalDateTime.now());
            }
            // 推迟三秒执行任务
        }, 3, TimeUnit.SECONDS);
    }

    /**
     * newScheduledThreadPool：创建执行定时任务的线程池
     */
    public void test4() {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
        System.out.println("添加任务：" + LocalDateTime.now());
        // test4_1(service);
        test4_2(service);
    }

    /**
     * 执行一次的定时任务
     * 
     * @param service
     */
    public void test4_1(ScheduledExecutorService service) {
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务：" + LocalDateTime.now());
            }
            // 推迟三秒执行
        }, 3, TimeUnit.SECONDS);
    }

    /**
     * 执行多次定时任务
     * 
     * @param service
     */
    public void test4_2(ScheduledExecutorService service) {
        service.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务：" + LocalDateTime.now() + "线程名：" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000 * 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }

            }
        }, 3, 2, TimeUnit.SECONDS);
    }

    /**
     * newWorkStealingPool:根据当前设备生成线程池
     */
    public void test5() {
        ExecutorService service = Executors.newWorkStealingPool();
        for (int i = 0; i < 50; i++) {
            int a = i;
            service.submit(() -> {
                // 线程名有多少，cpu就创建了多少个线
                System.out.println(a + "线程名" + Thread.currentThread().getName());
            });
        }
        // 创建守护线程，jvm不会等待守护线程结束
        while (!service.isTerminated()) {

        }
    }

    /**
     * 手动创建线程池
     */
    public void test6() {
        // 线程工厂
        ThreadFactory factory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                return null;
            }
        };
        ThreadPoolExecutor threadPoolExecutor =
            new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), factory,
                // 1.提示异常，拒绝执行多余的任务
                // new ThreadPoolExecutor.AbortPolicy()
                // 2.忽略堵塞队列中最旧的任务
                // new ThreadPoolExecutor.DiscardOldestPolicy()
                // 3.忽略最新的任务
                // new ThreadPoolExecutor.DiscardPolicy()
                // 4.使用调用该线程池的线程来执行任务
                // new ThreadPoolExecutor.CallerRunsPolicy()
                // 5.自定义拒绝策略
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("拒绝策略");
                    }
                });
        // 任务数
        for (int i = 0; i < 50; i++) {
            int a = i;
            threadPoolExecutor.submit(() -> {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + "任务名" + a);
            });
        }
    }

    public static void main(String[] args) {
        ExecutorsThreadPool executorsThreadPool = new ExecutorsThreadPool();
        executorsThreadPool.test6();
    }
}
